package net.facelib.sdk;

import static net.facelib.sdk.FaceCaptureLog.CAPTURER_LOGGER;

import java.util.HashMap;
import java.util.Iterator;
import java.util.ServiceLoader;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import net.gdface.utils.ThreadFactoryBuilder;

class FaceCapturerSupport {

	/**
	 * 应用层提供的{@link FaceCaptureHandler}接口实例,未提供则值为{@code null}
	 */
	static final HashMap<String, FaceCaptureHandler> captureInstances;
	/**
	 * 默认实例,如果SPI加载没有找到{@link FaceCapturer}实例则默认为{@code null}
	 */
	static FaceCapturer instance;

	private FaceCapturerSupport() {
	}
	static{
		captureInstances = FaceCapturerSupport.loadCaptureHandler();
		for(FaceCaptureHandler h:FaceCapturerSupport.captureInstances.values()){
			if(h instanceof FaceCapturer){
				instance = (FaceCapturer)h;
				CAPTURER_LOGGER.log("DEFAULT INSTANCE {} ({})",instance,instance.getProductID());
				break;
			}
		}
	}
	/**
	 * SPI(Service Provider Interface)机制加载 {@link FaceCaptureHandler}实例,没有找到返回空map
	 */
	static HashMap<String, FaceCaptureHandler> loadCaptureHandler() {		
		ServiceLoader<FaceCaptureHandler> providers = ServiceLoader.load(FaceCaptureHandler.class);
		HashMap<String, FaceCaptureHandler> capturers = new HashMap<>();
		for(Iterator<FaceCaptureHandler> itor = providers.iterator();itor.hasNext();){
			try {
				FaceCaptureHandler handler = itor.next();
				String productId = handler.getProductID();
				CAPTURER_LOGGER.log("FOUND {} for {}",handler,productId);
				if(null != productId && !productId.isEmpty()){
					capturers.put(productId, handler);
				}
			} catch (Throwable e) {
				CAPTURER_LOGGER.log("{}:{}",e.getClass().getName(),e.getMessage());
				CAPTURER_LOGGER.logTrace(e);
			}
		}
		return capturers;
	}
	final static Executor executor = SingletonExecutor.DISCARD_EXECUTOR;
	private static class SingletonExecutor{
		/** 
		 * 默认单线程池对象,用于活体检测和特征提取及识别<br>
		 * 使用放弃策略({@link ThreadPoolExecutor.DiscardPolicy}),即线程池中有任务未完成时,放弃新加任务 
		 */
		private static final ExecutorService DISCARD_EXECUTOR = new ThreadPoolExecutor(1, 1,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(1),
                new ThreadFactoryBuilder().setNameFormat("feature-live-%d").setDaemon(true).build(),
                new ThreadPoolExecutor.DiscardPolicy());
		static{
			ThreadFactoryBuilder.addDelayedShutdownHook(DISCARD_EXECUTOR, 20, TimeUnit.SECONDS);
		}
	}
	static Executor getExecutor() {
		return executor;
	}

}
